/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package se.kth.lwr.jeat.utils;

import java.util.ArrayList;
import java.util.List;
import javax.measure.quantity.Length;
import org.jscience.physics.amount.Amount;
import se.kth.lwr.jeat.core.*;

/**A class for representation of transport activities. It shares common properties
 * of transports as managing filling degrees and doing transport work. The usage of 
 * this class should follow the steps:
 * <ol>
 * <li>create an instance</li>
 * <li>describe the transport route through subsequent calls to {@code transport(distance, fill)}</li>
 * <li>retrieve the resulting activity through {@code getRouteActivity(name, desc)}</li>
 * </ol>
 *
 * @author davidev
 */
public abstract class Transportation {
    //current value of the filling degree for the transport

    private double fill = 0;
    //list of subactivities in this transportation activity
    private List<Activity> activities;
    //name of transport
    private String name;
    
    /**Creates a new empty transportation
     * 
     * @param name name of the transportation
     */
    public Transportation(String name) {
        this.activities = new ArrayList<>();
        this.name = name;
        
    }

    public String getName() {
        return name;
    }
    
    /**Returns the current sub activities as a List
     * 
     * @return the current sub activities 
     */

    protected List<Activity> getActivities() {
        return activities;
    }
    
    /**
     * Get the current filling degree for this transportation
     *
     * @return the current filling degree (a value between 0 and 1)
     */
    public double getFill() {
        return fill;
    }

    /**
     * Set the filling degree of this transportation
     *
     * @param fill filling degree (a value between 0 and 1)
     */
    public void setFill(double fill) {
        if (fill <= 1 && fill >= 0) {
            this.fill = fill;
        } else {
            throw new IllegalArgumentException("filling degree not within required bounderies (0-1)");
        }
    }

    /**
     * Requests a transport with user defined distance and current filling
     * degree
     *
     * @param distance
     * @return the transportation in updated state
     */
    public Transportation transport(Amount<Length> distance, String comment) {
        activities.add(getTransportActivity(distance, getFill(), comment));
        return this;

    }

    /**
     * Requests a transport with user defined distance and filling degree
     *
     * @param distance
     * @param fill
     * @return the transportation in updated state
     */
    public Transportation transport(Amount<Length> distance, double fill, String comment) {
        activities.add(getTransportActivity(distance, fill, comment));
        return this;
    }

    /**
     * Returns an activity that include all sub transports performed in this
     * transportation. If there is only one transport, this will be returned
     * alone. If no transport has been performed an IllegalStateException will 
     * be thrown. The activity and sub activities returned by this method will be
     * joined to the category {@link ActivityCategory.TRANSPORT}
     *
     * @param name activity name
     * @param description activity description
     * @return an activity for this transportation
     */
    public Activity getRouteActivity(String name, String description) {
        if (activities.isEmpty()){
            throw new IllegalStateException("No transports have been performed in this transportation");
        }else if(activities.size()==1){
            Activity retval=activities.get(0);
            retval.joinCategory(ActivityCategory.TRANSPORT);
            return retval;
        }else {
            Activity umberella = new UmberellaActivity(name, description);
            for (Activity activity : activities) {               
                umberella.addChild(activity);
            }
            umberella.joinCategoryDeep(ActivityCategory.TRANSPORT);
            return umberella;
        }

    }
    
    /**
     * Repeat the transportation sequence expressed in the passed argument. The
     * repetition will be expressed as a multiplication with a repeat constant instead
     * of producing separate activities for each repeat.
     * 
     * @param sequence the activity that that compose the transport sequence
     * @param repetitions the number of times to repeat the the route sequence
     * @return this transportation
     */
    public Transportation repeatRoutSequence(Transportation sequence, double repetitions){
        //wrap repetions
        final AmountDataSource timesDS=new AmountDataSource("repetition", "number of repetions of transport route", Amount.ONE.times(repetitions));
        //create an activity that represents the repetition 
        Activity repActivity=new Activity("Route sequence repeat", "repetition of child transports"){

            @Override
            public Inventory contribute(Inventory inventory) {
                //multiplies the child inventories by the given factor
                return inventory.multiply(timesDS.useValue(this));
            }
            
        };
        //copy the children over to the new repActivivty
        for(Activity route : sequence.getActivities()){
            repActivity.addChild(route);
        };
        //add the repActivity to this transport sequence
        getActivities().add(repActivity);
        //mark it with TRANSPORT
        repActivity.joinCategory(ActivityCategory.TRANSPORT);
        // ready to go
        return this;
        
    }

    /**
     * This method should return a valid activity with the inner details of this
     * transportation and the passed distance and fill.
     *
     * @param distance transport distance
     * @param fill filling degree
     * @return an Activity for the transport
     */
    protected abstract Activity getTransportActivity(Amount<Length> distance, double fill, String comment);
}
